import apcslib.*;
import java.awt.*;
import java.util.ArrayList;

@SuppressWarnings("serial")
public class GraphPanel extends SketchPadPanel{
	DrawingTool pencil;
	final Color[] GRAPH_COLORS = {Color.BLACK, Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW, new Color(255,100,0), Color.PINK, Color.LIGHT_GRAY, Color.CYAN};
	final String[] GRAPH_COLOR_STRINGS = {"Black","Red","Green","Blue","Yellow","Orange","Pink","Gray","Cyan"};
	int myX, myY;
	Legend myLegend;
	public GraphPanel(int x, int y){
		super(0);
		myX = x;
		myY = y;
		pencil = new DrawingTool(this);
		myLegend = new Legend();
	}
	
	public Legend getLegend(){
		return myLegend;
	}
	
	public void drawGraph(ArrayList<Student> student_data, ArrayList<String> axisLabels){
		myLegend.clearLegend();
		double[][] data = new double[student_data.size()][axisLabels.size()];
		boolean color_cat = false; //True indicates that color axis is being used for Strings or bools
		for(int i = 0; i < axisLabels.size(); i++){
			String label = axisLabels.get(i);
			if(label.equals("")){
				for(int j = 0; j < student_data.size(); j++){
					data[j][i] = 0;
				}
			}
			if(label.equals("Age")){
				for(int j = 0; j < student_data.size(); j++){
					data[j][i] = student_data.get(j).getAge();
				}
				double max = findMax(data,i);
				double min = findMin(data,i,max);
				myLegend.addLegendEntry(i,"Min",String.format("%.2f", min));
				myLegend.addLegendEntry(i,"Max",String.format("%.2f", max));
			}
			if(label.equals("GPA")){
				for(int j = 0; j < student_data.size(); j++){
					data[j][i] = student_data.get(j).getGpa();
				}
				double max = findMax(data,i);
				double min = findMin(data,i,max);
				myLegend.addLegendEntry(i,"Min",String.format("%.2f", min));
				myLegend.addLegendEntry(i,"Max",String.format("%.2f", max));
			}
			if(label.equals("Year")){
				ArrayList<String> itemList = new ArrayList<String>();
				if(i==2){
					color_cat = true;
				}
				for(int j = 0; j < student_data.size(); j++){
					String year = student_data.get(j).getClass_year();
					if(!itemList.contains(year)){
						itemList.add(year);
						if(i==2){
							myLegend.addLegendEntry(i, GRAPH_COLOR_STRINGS[itemList.indexOf(year)], year);
						}
						else{
							myLegend.addLegendEntry(i, itemList.indexOf(year)+"", year);
						}
					}
					data[j][i] = itemList.indexOf(year);
				}
			}
			if(label.equals("Major")){
				ArrayList<String> itemList = new ArrayList<String>();
				if(i==2){
					color_cat = true;
				}
				for(int j = 0; j < student_data.size(); j++){
					String major = student_data.get(j).getMajor();
					if(!itemList.contains(major)){
						itemList.add(major);
						if(i==2){
							myLegend.addLegendEntry(i, GRAPH_COLOR_STRINGS[itemList.indexOf(major)], major);
						}
						else{
							myLegend.addLegendEntry(i, itemList.indexOf(major)+"", major);
						}
					}
					data[j][i] = itemList.indexOf(major);
					
				}
			}
			if(label.equals("Height")){
				for(int j = 0; j < student_data.size(); j++){
					data[j][i] = student_data.get(j).getHeight();
				}
				double max = findMax(data,i);
				double min = findMin(data,i,max);
				myLegend.addLegendEntry(i,"Min",String.format("%.2f", min));
				myLegend.addLegendEntry(i,"Max",String.format("%.2f", max));
			}
			if(label.equals("Weight")){
				for(int j = 0; j < student_data.size(); j++){
					data[j][i] = student_data.get(j).getWeight();
				}
				double max = findMax(data,i);
				double min = findMin(data,i,max);
				myLegend.addLegendEntry(i,"Min",String.format("%.2f", min));
				myLegend.addLegendEntry(i,"Max",String.format("%.2f", max));
			}
			if(label.equals("Avg Credit Hours")){
				for(int j = 0; j < student_data.size(); j++){
					data[j][i] = student_data.get(j).getCredit_hour_ave();
				}
				double max = findMax(data,i);
				double min = findMin(data,i,max);
				myLegend.addLegendEntry(i,"Min",String.format("%.2f", min));
				myLegend.addLegendEntry(i,"Max",String.format("%.2f", max));
			}
			if(label.equals("Favorite Food")){
				if(i==2){
					color_cat = true;
				}
				ArrayList<String> itemList = new ArrayList<String>();
				for(int j = 0; j < student_data.size(); j++){
					String food = student_data.get(j).getFavorite_food();
					if(!itemList.contains(food)){
						itemList.add(food);
						if(i==2){
							myLegend.addLegendEntry(i, GRAPH_COLOR_STRINGS[itemList.indexOf(food)], food);
						}
						else{
							myLegend.addLegendEntry(i, itemList.indexOf(food)+"", food);
						}
					}
					data[j][i] = itemList.indexOf(food);
				}
			}
			if(label.equals("# of Absences")){
				for(int j = 0; j < student_data.size(); j++){
					data[j][i] = student_data.get(j).getAbscences();
				}
				double max = findMax(data,i);
				double min = findMin(data,i,max);
				myLegend.addLegendEntry(i,"Min",String.format("%.2f", min));
				myLegend.addLegendEntry(i,"Max",String.format("%.2f", max));
			}
			if(label.equals("Employed?")){
				if(i == 2){
					color_cat = true;
				}
				for(int j = 0; j < student_data.size(); j++){
					if(student_data.get(j).isIs_employed()){
						data[j][i] = 1;
					}
					else{
						data[j][i] = 0;
					}
				}
				if(i==2){
					myLegend.addLegendEntry(i, GRAPH_COLOR_STRINGS[0], "Unemployed");
					myLegend.addLegendEntry(i, GRAPH_COLOR_STRINGS[1], "Employed");
				}
				else{
					myLegend.addLegendEntry(i, 0 + "", "Unemployed");
					myLegend.addLegendEntry(i, 1 + "", "Employed");
				}
			}
		}
		draw4DGraph(data,color_cat);
	}
	
	//Draws a standard x-y graph, varies the color scheme to account for the z-term, and varies the size
	//to account for the w-term. color_cat indicates whether the z-term is discrete or continuous to allow
	//better coloring for the situation
	public void draw4DGraph(double[][] data,boolean color_cat){
		pencil.setColor(Color.WHITE);
		pencil.move(0,0);
		pencil.fillRect(1.5*myX, 1.5*myY);
		double maxX = findMax(data, 0);
		double maxY = findMax(data, 1);
		double maxZ = findMax(data, 2);
		double maxW = findMax(data, 3);
		double minX = findMin(data, 0, maxX);
		double minY = findMin(data, 1, maxY);
		double minZ = findMin(data, 2, maxZ);
		double minW = findMin(data, 3, maxW);
		if(minX != maxX){
			if(maxX-minX < 4){
				drawXAxis(minX, maxX, 4);
			}
			else if(maxX-minX > 12){
				drawXAxis(minX, maxX, 12);
			}
			else{
				drawXAxis(minX, maxX, (int)(maxX-minX));
			}
		}
		if(minY != maxY){
			if(maxY-minY < 5){
				drawYAxis(minY, maxY, 5);
			}
			else if(maxY-minY > 15){
				drawYAxis(minY, maxY, 15);
			}
			else{
				drawYAxis(minY, maxY, (int)(maxY-minY));
			}
		}
		for(int i = 0; i< data.length; i++){
			if(minZ != maxZ){
				if(color_cat){
					pencil.setColor(GRAPH_COLORS[(int)data[i][2]]);
				}
				else{
					pencil.setColor(new Color(0,(int)((data[i][2]-minZ)/(maxZ-minZ)*200),0));
				}
			}
			else{
				pencil.setColor(Color.BLACK);
			}
			pencil.up();
			if(minX != maxX && minY != maxY){
				pencil.move((data[i][0]-minX)/(maxX-minX)*(0.90*myX)-(0.90*myX)/2, (data[i][1]-minY)/(maxY-minY)*(0.80*myY)-(0.80*myY)/2);
			}
			else if(minX != maxX){
				pencil.move((data[i][0]-minX)/(maxX-minX)*(0.90*myX)-(0.90*myX)/2, 0);
			}
			else if(minY != maxY){
				pencil.move(0, (data[i][1]-minY)/(maxY-minY)*(0.80*myY)-(0.80*myY)/2);
			}
			else{
				pencil.move(0, 0);
			}
			pencil.down();
			if(minW != maxW){
				pencil.fillOval(7.5+(data[i][3]-minW)/(maxW-minW)*10.0,7.5+(data[i][3]-minW)/(maxW-minW)*10.0);
			}
			else{
				pencil.fillOval(7.5, 7.5);
			}
		}
		//repaint();
	}
	
	public double findMax(double[][] data, int index){
		double max = 0;
		for(int i = 0; i < data.length; i++){
			if(data[i][index] > max){
				max = data[i][index];
			}
		}
		return max;
	}
	
	public double findMin(double[][] data, int index, double max){
		double min = max;
		for(int i = 0; i < data.length; i++){
			if(data[i][index] < min){
				min = data[i][index];
			}
		}
		return min;
	}
	
	public void drawXAxis(double max, double min, int numTicks){
		pencil.setColor(Color.BLACK);
		pencil.up();
		pencil.move(-0.9*myX/2, -0.8*myY/2);
		pencil.down();
		pencil.move(myX/2, -0.8*myY/2);
		double x = min;
		pencil.up();
		for(int i = 0; i <= numTicks; i++){
			if(i!=numTicks){
				pencil.move(0.897*myX/2 - (myX/numTicks)*i*.90, -0.82 * myY/2);
				pencil.down();
				pencil.move(0.897*myX/2 - (myX/numTicks)*i*.90, -0.78 * myY/2);
				pencil.up();
			}
			pencil.move(0.9*myX/2 - (myX/numTicks)*i*.90, -0.85*myY/2);
			String s = String.format("%.2f", x);
			pencil.drawString(s);
			x += (max - min)/numTicks;
		}
	}
	
	public void drawYAxis(double max, double min, int numTicks){
		pencil.setColor(Color.BLACK);
		pencil.up();
		pencil.move(-0.9*myX/2, -0.8*myY/2);
		pencil.down();
		pencil.move(-0.9*myX/2, myY/2);
		double y = min;
		pencil.up();
		for(int i = 0; i <= numTicks; i++){
			if(i != numTicks){
				pencil.move(-0.92*myX/2, 0.797 * myY/2 - (myY/numTicks)*i*0.8);
				pencil.down();
				pencil.move(-0.88*myX/2, 0.797 * myY/2 - (myY/numTicks)*i*0.8);
				pencil.up();
			}
			String s = String.format("%.2f", y);
			pencil.move((-0.9-0.03*(s.length()))*myX/2, 0.81 * myY/2 - (myY/numTicks)*i*0.8);
			pencil.drawString(s);
			y += (max - min)/numTicks;
		}
	}
}
